package org.gavin.core.advice;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.gavin.core.annotation.AccessLimit;
import org.gavin.core.enums.CommonStatus;
import org.gavin.core.exception.AccessException;
import org.gavin.core.service.limit.AccessLimitAbstract;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;

/**
 * AccessLimitAdvice
 *
 * @author grl
 * @date 2024/1/24
 */
@Slf4j
@Aspect
@Order(101)
@Component
@RequiredArgsConstructor
public class AccessLimitAdvice {

    private final AccessLimitAbstract accessLimitAbstract;

    /**
     * 切入点
     */
    @Pointcut("@annotation(org.gavin.core.annotation.AccessLimit)" +
            " && (@target(org.springframework.web.bind.annotation.RestController)" +
            " ||   @target(org.springframework.stereotype.Controller))")
    public void pointCut() {
    }

    /**
     * 环绕 : 此方法是出参打印，
     *
     * @param proceedingJoinPoint
     * @return
     * @throws Throwable
     */
    @Around("pointCut() && @annotation(limit)")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint,AccessLimit limit) throws Throwable {
        Signature signature = proceedingJoinPoint.getSignature();
        String declaringTypeName = signature.getDeclaringTypeName();
        String name = signature.getName();
        Object[] args = proceedingJoinPoint.getArgs();
        String  methodName = declaringTypeName +"#"+name;
        boolean flag = accessLimitAbstract.accessDenied(limit,methodName, args);
        if(flag){
            throw AccessException.le(CommonStatus.ACCESS_LIMIT,methodName,null);
        }
        return proceedingJoinPoint.proceed();
    }
}
